package com.lzqinga.service;

import com.google.gson.Gson;
import com.lzqinga.config.XfApiConfig;
import okhttp3.HttpUrl;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * - @author lzqinga
 * - @description
 * - @date 2025/10/10/010 13:24
 **/
@Service
public class XunFeiService {

    @Autowired
    XfApiConfig xfApiConfig;

    public static final String hostUrl = "https://tts-api.xfyun.cn/v2/tts";
    // 均到控制台-语音合成页面获取
//    public static final String APPID = "0634a9cf";
//    public static final String APISecret = "M2M2YmVlNGIxNGFhYTY2OWY0YTBiNWY5";
//    public static final String APIKey = "27b9e4aebd65372c49f9ab295348a313";
    // 合成文本
    public static final String TEXT = "故宫的雪是雪天的雪，茫茫沧海中，唯有你来过，砖瓦从中过，飘然洁如羽";
    // 合成文本编码格式
    public static final String TTE = "UTF8"; // 小语种必须使用UNICODE编码作为值
    // 发音人参数。到控制台-我的应用-语音合成-添加试用或购买发音人，添加后即显示该发音人参数值，若试用未添加的发音人会报错11200
    public static final String VCN = "x4_yezi";
    // 合成文件存储地址以及名称
    public static final String OUTPUT_FILE_PATH = "output/videos/" + System.currentTimeMillis() + ".mp3";
    // json
    public static final Gson gson = new Gson();
    // 移除静态变量，使用实例变量
    private CountDownLatch completionLatch;
    private volatile boolean success = false;
    private volatile String errorMessage;
    private String requestSid;

//    public static void main(String[] args) throws Exception {
//        String wsUrl = getAuthUrl(hostUrl, APIKey, APISecret).replace("https://", "wss://");
//        OutputStream outputStream = new FileOutputStream(OUTPUT_FILE_PATH);
//        websocketWork(TEXT, wsUrl, outputStream);
//    }

    public void tts(String content, String path) throws Exception {
        String wsUrl = getAuthUrl(hostUrl, xfApiConfig.getApiKey(), xfApiConfig.getApiSecret()).replace("https://", "wss://");
        try (OutputStream outputStream = new FileOutputStream(path)) {
            websocketWork(content, wsUrl, outputStream);
        }

        if (!success) {
            throw new IOException("语音合成失败: " + (errorMessage != null ? errorMessage : "未知错误"));
        }
    }

    // Websocket方法
    public void websocketWork(String content, String wsUrl, OutputStream outputStream) {
        completionLatch = new CountDownLatch(1);
        success = false;
        errorMessage = null;
        requestSid = null;

        try {
            URI uri = new URI(wsUrl);
            WebSocketClient webSocketClient = new WebSocketClient(uri) {
                @Override
                public void onOpen(ServerHandshake serverHandshake) {
                    System.out.println("WS连接建立成功...");

                    // 启动线程发送数据
                    Thread sendThread = new Thread(new SendRunnable(content, this, outputStream));
                    sendThread.start();
                }

                @Override
                public void onMessage(String text) {
                    try {
                        JsonParse myJsonParse = gson.fromJson(text, JsonParse.class);
                        requestSid = myJsonParse.sid;

                        if (myJsonParse.code != 0) {
                            errorMessage = "服务器返回错误，错误码: " + myJsonParse.code;
                            System.err.println(errorMessage);
                            completionLatch.countDown();
                            return;
                        }

                        if (myJsonParse.data != null) {
                            synchronized (outputStream) {
                                byte[] audioData = Base64.getDecoder().decode(myJsonParse.data.audio);
                                outputStream.write(audioData);
                                outputStream.flush();
                            }

                            if (myJsonParse.data.status == 2) {
                                success = true;
                                System.out.println("语音合成完成，SID: " + requestSid);
                                completionLatch.countDown();
                            }
                        }
                    } catch (Exception e) {
                        errorMessage = "处理消息时发生错误: " + e.getMessage();
                        System.err.println(errorMessage);
                        completionLatch.countDown();
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    System.out.println("WS连接关闭，代码: " + code + ", 原因: " + reason);
                    if (!success) {
                        errorMessage = "连接过早关闭，合成可能未完成";
                    }
                    completionLatch.countDown();
                }

                @Override
                public void onError(Exception e) {
                    errorMessage = "WS连接错误: " + e.getMessage();
                    System.err.println(errorMessage);
                    completionLatch.countDown();
                }
            };

            // 建立连接
            webSocketClient.connect();

            // 等待操作完成，设置超时时间
            if (!completionLatch.await(120, TimeUnit.SECONDS)) {
                throw new RuntimeException("语音合成超时");
            }

        } catch (Exception e) {
            throw new RuntimeException("语音合成失败: " + e.getMessage(), e);
        }
    }

    // 发送数据的Runnable实现
    private class SendRunnable implements Runnable {
        private final String text;
        private final WebSocketClient webSocketClient;
        private final OutputStream outputStream;

        public SendRunnable(String text, WebSocketClient webSocketClient, OutputStream outputStream) {
            this.text = text;
            this.webSocketClient = webSocketClient;
            this.outputStream = outputStream;
        }

        @Override
        public void run() {
            try {
                // 等待连接完全建立
                int maxWait = 5000; // 5秒超时
                int waited = 0;
                while (!webSocketClient.getReadyState().equals(WebSocket.READYSTATE.OPEN)){
                    Thread.sleep(100);
                    waited += 100;
                    if (waited >= maxWait) {
                        throw new RuntimeException("WebSocket连接建立超时");
                    }
                }

                String requestJson = buildRequestJson(text);
                webSocketClient.send(requestJson);

            } catch (Exception e) {
                errorMessage = "发送数据时发生错误: " + e.getMessage();
                System.err.println(errorMessage);
                completionLatch.countDown();
            }
        }
    }

    // 构建请求JSON
    private String buildRequestJson(String text) {
        Map<String, Object> common = new HashMap<>();
        common.put("app_id", xfApiConfig.getAppId());

        Map<String, Object> business = new HashMap<>();
        business.put("aue", "lame");
        business.put("tte", TTE);
        business.put("ent", "intp65");
        business.put("vcn", VCN);
        business.put("pitch", 50);
        business.put("speed", 50);

        Map<String, Object> data = new HashMap<>();
        data.put("status", 2);
        data.put("text", Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8)));

        Map<String, Object> request = new HashMap<>();
        request.put("common", common);
        request.put("business", business);
        request.put("data", data);

        return gson.toJson(request);
    }


    // 线程来发送音频与参数
//    static class MyThread extends Thread {
//        WebSocketClient webSocketClient;
//
//        String text;
//
//        public MyThread(String text, WebSocketClient webSocketClient) {
//            this.text = text;
//            this.webSocketClient = webSocketClient;
//        }
//
//        public void run() {
//            String requestJson;//请求参数json串
//            try {
//                requestJson = "{\n" +
//                        "  \"common\": {\n" +
//                        "    \"app_id\": \"" + APPID + "\"\n" +
//                        "  },\n" +
//                        "  \"business\": {\n" +
//                        "    \"aue\": \"lame\",\n" +
//                        "    \"tte\": \"" + TTE + "\",\n" +
//                        "    \"ent\": \"intp65\",\n" +
//                        "    \"vcn\": \"" + VCN + "\",\n" +
//                        "    \"pitch\": 50,\n" +
//                        "    \"speed\": 50\n" +
//                        "  },\n" +
//                        "  \"data\": {\n" +
//                        "    \"status\": 2,\n" +
//                        "    \"text\": \"" + Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8)) + "\"\n" +
//                        "  }\n" +
//                        "}";
//                webSocketClient.send(requestJson);
//                // 等待服务端返回完毕后关闭
//                while (!wsCloseFlag) {
//                    Thread.sleep(200);
//                }
//                webSocketClient.close();
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//    }

    // 鉴权方法
    public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        // 时间
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        // 拼接
        String preStr = "host: " + url.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + url.getPath() + " HTTP/1.1";
        //System.out.println(preStr);
        // SHA256加密
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
        // Base64加密
        String sha = Base64.getEncoder().encodeToString(hexDigits);
        // 拼接
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
        // 拼接地址
        HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath())).newBuilder().//
                addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).//
                addQueryParameter("date", date).//
                addQueryParameter("host", url.getHost()).//
                build();

        return httpUrl.toString();
    }

    //返回的json结果拆解
    class JsonParse {
        int code;
        String sid;
        Data data;
    }

    class Data {
        int status;
        String audio;
    }
}
